/*******************************************************************************
 File Name        : freyabasecontrol.h
 Summary          : FreyaLib`s control
 Create           : 2015-04-27
 Author           : Schindleren
 Update history   : (Look up at freyabasecontrol.h)
*******************************************************************************/
#include "freyabasecontrol.h"
#include "freyabaseaction.h"
#include "freyapublicregister.h"
#include <QDateTime>

FreyaBaseControl::FreyaBaseControl() :
    FreyaAbstractControl(), m_CMDDistribution(this)
{
    m_CMDDistribution.start(QThread::TimeCriticalPriority);
}

QString FreyaBaseControl::FreyaVersion()
{
    return FREYAVER;
}

FreyaBaseControl::~FreyaBaseControl()
{
    qDebug() << "FreyaLib > " << "Destructor" << this;
}

QVariantMap FreyaBaseControl::GetConfigFromFile(const QString &filePath)
{
    return m_FreyaPublicRegister.GetConfigFromFile(filePath);
}

bool FreyaBaseControl::SetConfigToFile(const QString &filePath, const QVariantMap &varmap)
{
    return m_FreyaPublicRegister.SetConfigToFile(filePath, varmap);
}

QVariant FreyaBaseControl::GetConfig(const QStringList &configPath)
{
    return m_FreyaPublicRegister.GetConfig(configPath);
}

bool FreyaBaseControl::SetConfig(const QStringList &configPath, const QVariant &var)
{
    return m_FreyaPublicRegister.SetConfig(configPath, var);
}

bool FreyaBaseControl::InsertConfig(const QStringList &configPath, const QVariant &var)
{
    return m_FreyaPublicRegister.InsertConfig(configPath, var);
}

bool FreyaBaseControl::RemoveConfig(const QStringList &configPath)
{
    return m_FreyaPublicRegister.RemoveConfig(configPath);
}

bool FreyaBaseControl::RegisterObject(FreyaBaseAction *actObject, const char *actionName)
{
    return m_FreyaPublicRegister.RegisterObject(actObject, actionName);
}

bool FreyaBaseControl::UnRegisterObject(const QString &actionName)
{
    int successCount = 0;
    QList<FreyaBaseAction*> listActions = FindActionObject(actionName);
    foreach(FreyaBaseAction* pAction, listActions)
    {
        if(m_FreyaPublicRegister.UnRegisterObject(pAction))
        {
            ++successCount;
        }
    }
    return (listActions.count() == successCount);
}

bool FreyaBaseControl::UnRegisterObject(FreyaBaseAction *actObject)
{
    return m_FreyaPublicRegister.UnRegisterObject(actObject);
}

bool FreyaBaseControl::RegisterCommand(FreyaBaseAction *actObject, QList<quint64> commandList)
{
    qInfo() << "FreyaLib > " << "RegisterCommand object:" << FindActionName(actObject) << "command count:" << commandList.size();
    foreach (const quint64 &command, commandList)
    {
        qInfo() << "    " << CmdLogString(command);
    }
    return m_FreyaPublicRegister.RegisterCommand(actObject, commandList);
}

bool FreyaBaseControl::UnRegisterCommand(FreyaBaseAction *actObject)
{
    qDebug() << "FreyaLib > " << "UnRegisterCommand object:" << FindActionName(actObject);
    return m_FreyaPublicRegister.UnRegisterCommand(actObject);
}

QList<FreyaBaseAction*> FreyaBaseControl::FindActionObject(const QString &actionName)
{
    return m_FreyaPublicRegister.FindActionObject(actionName);
}

QString FreyaBaseControl::FindActionName(FreyaBaseAction *actObject)
{
    return m_FreyaPublicRegister.FindActionName(actObject);
}

void FreyaBaseControl::DeleteAllAction(const QList<FreyaBaseAction *> &except)
{
    QList<FreyaBaseAction *> ActionList = m_FreyaPublicRegister.AllRegisterAction().keys();
    foreach (FreyaBaseAction *pAction, ActionList)
    {
        if(!except.contains(pAction))
        {
            delete pAction;
        }
    }
}

void FreyaBaseControl::DeleteAllAction(const QStringList &except)
{
    QList<FreyaBaseAction *> ActionList;
    foreach (const QString &ActionName, except)
    {
        ActionList.append(m_FreyaPublicRegister.FindActionObject(ActionName));
    }
    DeleteAllAction(ActionList);
}

bool FreyaBaseControl::InsertFreyaData(const FreyaData pData)
{
    return m_FreyaPublicRegister.InsertFreyaData(pData);
}

FreyaData FreyaBaseControl::FindFreyaData(const QString &dataID)
{
    return m_FreyaPublicRegister.FindFreyaData(dataID);
}

FreyaData FreyaBaseControl::TakeFreyaData(const QString &dataID)
{
    return m_FreyaPublicRegister.TakeFreyaData(dataID);
}

bool FreyaBaseControl::RequestExecution(void *pRequester)
{
    qDebug() << "FreyaLib > " << "Execution: without arguments From:" << pRequester;
    bool r = false;
    m_pRequester = pRequester;
    QHashIterator<FreyaBaseAction*, QString> ActionIt(m_FreyaPublicRegister.AllRegisterAction());
    while (ActionIt.hasNext())
    {
        ActionIt.next();
        r = true;
        FreyaBaseAction *pAction = ActionIt.key();
        if(pAction)
        {
            pAction->Execute();
        }
    }
    m_pRequester = nullptr;
    return r;
}

bool FreyaBaseControl::RequestExecution(const quint64 &command, void *pRequester, int msec)
{
    return RequestExecution(FreyaBaseData::CreateData(command), pRequester, msec);
}

bool FreyaBaseControl::RequestExecution(const FreyaData pData, void *pRequester, int msec)
{
    if(pData.isNull())
    {
        return false;
    }
    pData->SetProperty(FREYALIB_FLG_REQUESTER, CUSTOMCLSTOVARIANT(pRequester));
    pData->SetProperty(FREYALIB_FLG_WAITTIME, msec);
    pData->SetProperty(FREYALIB_FLG_TIMESTAMP, QDateTime::currentDateTime());

    if(msec)
    {
        QSharedPointer<QSemaphore> shareSem(new QSemaphore());
        m_FreyaPublicRegister.InsertFreyaData(pData);
        bool ret = m_FreyaPublicRegister.InsertQuerySymbol(pData->dataID, shareSem);

        m_CMDDistribution.InsertData(pData);

        if(m_FreyaPublicRegister.CheckQuerySymbol(pData->dataID))
        {
            ret = (ret && (shareSem->tryAcquire(1, msec)));
        }
        else
        {
            qWarning() << "FreyaLib > " << "Query data is not exist! ID:" << pData->dataID
                       << "Command:" << CmdLogString(pData->command);
        }

        m_FreyaPublicRegister.TakeFreyaData(pData->dataID);
        ret = ((m_FreyaPublicRegister.TakeQuerySymbol(pData->dataID).isNull()) && ret);
        if(ret)
        {
            qDebug() << "FreyaLib > " << "Query: DataID:" << pData->dataID
                     << "Command:" << CmdLogString(pData->command)
                     /*<< "Property:" << pData->GetProperty() */<< "From:" << pRequester;
        }
        else
        {
            qWarning() << "FreyaLib > " << "Query failed: DataID:" << pData->dataID
                       << "Command:" << CmdLogString(pData->command) << "Wait:" << msec;
        }

        return ret;
    }
    else
    {
        m_CMDDistribution.InsertData(pData);
        return true;
    }
}

bool FreyaBaseControl::ReplyExecution(const FreyaData pData, void *pRequester)
{
    if(pData.isNull())
    {
        return false;
    }
    if(m_FreyaPublicRegister.CheckQuerySymbol(pData->dataID))
    {
        pData->SetProperty(FREYALIB_FLG_REQUESTER, CUSTOMCLSTOVARIANT(pRequester));
        QSharedPointer<QSemaphore> shareSem = m_FreyaPublicRegister.TakeQuerySymbol(pData->dataID);
        if(!shareSem.isNull())
        {
            qDebug() << "FreyaLib > " << "Reply:" << pData->dataID;
            shareSem->release();
        }
        else
        {
            qWarning() << "FreyaLib > " << "Later reply:" << pData->dataID << "Command:" << CmdLogString(pData->command);;
        }
        return true;
    }
    else
    {
        //接收到请求返回消息时，等待接收请求队列不存在此消息
        qWarning() << "FreyaLib > " << "Unknow replay:" << pData->dataID << "Command:" << CmdLogString(pData->command);
    }
    return false;
}

void FreyaBaseControl::AppendCmdLogString(const quint64 &command, const QString &LogStr)
{
    m_FreyaPublicRegister.AppendCmdLogString(command, LogStr);
    qDebug() << "FreyaLib > " << "Register cmd log string:" << LogStr << ("0x" + QString::number(command, 16).rightJustified(16, '0'));
}
